package com.itheima.trade.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.model.common.dtos.AccountDto;
import com.itheima.model.common.dtos.ResponseResult;
import com.itheima.model.common.enums.AppHttpCodeEnum;
import com.itheima.model.common.pojos.Account;
import com.itheima.trade.annotation.AutoLogFill;
import com.itheima.trade.mapper.AccountMapper;
import com.itheima.trade.service.AccountService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

@Service
@RequiredArgsConstructor
@Slf4j
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {

    private final AccountMapper accountMapper;

    /**
     * 转账
     * @param fromAccount
     * @param toAccount
     * @return
     */
    @Override
    @Transactional
    @AutoLogFill
    public ResponseResult transfer(AccountDto fromAccount, AccountDto toAccount) {
        try {
            // 从转出账户扣除余额
            withdraw(fromAccount);
            // 向转入账户增加余额
            toAccount.setTransferAmount(fromAccount.getTransferAmount());
            save(toAccount);
        } catch (Exception e) {
            // 重新抛出异常，让 Spring 管理事务回滚
            throw new RuntimeException("转账失败: " + e.getMessage(), e);
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 存钱
     *
     * @param accountDto
     * @return
     */
    @Override
    @AutoLogFill
    public ResponseResult saving(AccountDto accountDto) {
        try {
            save(accountDto);
        } catch (Exception e) {
            // 重新抛出异常，让 Spring 管理事务回滚
            throw new RuntimeException("充值失败: " + e.getMessage(), e);
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 取钱
     *
     * @param accountDto
     * @return
     */
    @Override
    @AutoLogFill
    public ResponseResult withdrawMoney(AccountDto accountDto) {
        try {
            withdraw(accountDto);
        } catch (Exception e) {
            // 重新抛出异常，让 Spring 管理事务回滚
            throw new RuntimeException("提现失败: " + e.getMessage(), e);
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    // 取钱
    public void withdraw(AccountDto accountDto) {
        log.info("开始执行取钱操作");
        try {
            // 获取取钱账户的数据
            Account accountData = accountMapper.selectOne(new QueryWrapper<Account>().eq("cardno", accountDto.getCardno()));
            if (accountData == null) {
                throw new RuntimeException("账户不存在");
            }
            // 判断余额是否充足
            BigDecimal amount = accountDto.getTransferAmount();
            BigDecimal balance = accountData.getRemaining();
            if (balance.compareTo(amount) < 0) {
                throw new RuntimeException("账户余额不足");
            }
            // 计算新的余额
            BigDecimal newBalance = accountData.getRemaining().subtract(accountDto.getTransferAmount());
            // 更新账户数据
            accountData.setRemaining(newBalance);
            accountMapper.updateById(accountData);
        } catch (RuntimeException e) {
            throw new RuntimeException(e);
        }
    }

    // 存钱
    public void save(AccountDto accountDto) {
        log.info("开始执行存钱操作");
        try {
            // 获取存钱账户的数据
            Account accountData = accountMapper.selectOne(new QueryWrapper<Account>().eq("cardno", accountDto.getCardno()));
            if (accountData == null) {
                throw new RuntimeException("账户不存在");
            }
            // 计算新的余额
            BigDecimal newBalance = accountData.getRemaining().add(accountDto.getTransferAmount());
            // 更新账户数据
            accountData.setRemaining(newBalance);
            accountMapper.updateById(accountData);
        } catch (RuntimeException e) {
            throw new RuntimeException(e);
        }
    }
}
